/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lvneng.processor;

import com.github.zengfr.easymodbus4j.func.request.*;
import com.github.zengfr.easymodbus4j.func.response.*;
import com.github.zengfr.easymodbus4j.processor.AbstractModbusProcessor;
import com.github.zengfr.easymodbus4j.processor.ModbusSlaveRequestProcessor;
import com.github.zengfr.easymodbus4j.sender.ChannelSender;
import com.lvneng.core.ModbusConsoleApp;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

import java.util.Arrays;
import java.util.BitSet;
import java.util.Random;

/**
 * @author zengfr QQ:362505707/1163551688 Email:zengfr3000@qq.com
 *         https://github.com/zengfr/easymodbus4j
 */
public class ExampleModbusSlaveRequestProcessor extends AbstractModbusProcessor implements ModbusSlaveRequestProcessor {
	private static final InternalLogger logger = InternalLoggerFactory.getInstance(ExampleModbusSlaveRequestProcessor.class);

	public ExampleModbusSlaveRequestProcessor(short transactionIdentifierOffset) {
		super(transactionIdentifierOffset, true);
	}

	/**
	 * 读线圈
	 * @param unitIdentifier //从站编号
	 * @param request
	 * @return
	 */
	@Override
	public ReadCoilsResponse readCoils(short unitIdentifier, ReadCoilsRequest request) {
		short functionCode = request.getFunctionCode();//功能码
		int startingAddress = request.getStartingAddress();//起始地址，寄存器读取开始地址
		int quantity = request.getQuantityOfCoils();//读取的数量，连续读取数量
		BitSet coils = getBitSet(unitIdentifier,functionCode,startingAddress,quantity);
		logger.debug("readCoils,unitIdentifier:" + unitIdentifier + ",functionCode:" + functionCode + ",startingAddress:" + startingAddress + ",quantity:" + quantity + ",coils:" + coils.toString());
		return new ReadCoilsResponse(coils);
	}

	/**
	 * 获取读线圈和读离散输入 所需的BitSet对象
	 * @param slaveId //从站编号
	 * @param functionCode
	 * @param startingAddress
	 * @param quantity
	 * @return
	 */
	private BitSet getBitSet(short slaveId,short functionCode,int startingAddress,int quantity){
		BitSet coils = new BitSet(quantity);
		Integer[] integerArray = DataMap.getBatchValue(slaveId,functionCode,startingAddress,quantity);
		int[] array = Arrays.stream(integerArray).mapToInt(Integer::intValue).toArray();
		for(int i=0;i<array.length;i++){
			int index = startingAddress + i;
			boolean value = false;
			if(array[i] == 1){
				value = true;
			}
			coils.set(index,value);
		}
		return coils;
	}

	/**
	 * 读离散输入
	 * @param unitIdentifier
	 * @param request
	 * @return
	 */
	@Override
	public ReadDiscreteInputsResponse readDiscreteInputs(short unitIdentifier, ReadDiscreteInputsRequest request) {
		short functionCode = request.getFunctionCode();//功能码
		int startingAddress = request.getStartingAddress();//起始地址，寄存器读取开始地址
		int quantity = request.getQuantityOfCoils();//读取的数量，连续读取数量
		BitSet coils = getBitSet(unitIdentifier,functionCode,startingAddress,quantity);
		logger.debug("readDiscreteInputs,unitIdentifier:" + unitIdentifier + ",functionCode:" + functionCode + ",startingAddress:" + startingAddress + ",quantity:" + quantity + ",coils:" + coils.toString());
		return new ReadDiscreteInputsResponse(coils);
	}

	/**
	 * 读输入寄存器（未测试）
	 * @param unitIdentifier
	 * @param request
	 * @return
	 */
	@Override
	public ReadInputRegistersResponse readInputRegisters(short unitIdentifier, ReadInputRegistersRequest request) {
		short slaveId = unitIdentifier;//从站编号
		short functionCode = request.getFunctionCode();//功能码
		int startingAddress = request.getStartingAddress();//起始地址，寄存器读取开始地址
		int quantity = request.getQuantityOfInputRegisters();//读取的寄存器数量，连续读取数量
		Integer[] integerArray = DataMap.getBatchValue(slaveId,functionCode,startingAddress,quantity);
		int[] array = Arrays.stream(integerArray).mapToInt(Integer::intValue).toArray();
		logger.debug("readInputRegisters,unitIdentifier:" + unitIdentifier + ",functionCode:" + functionCode + ",startingAddress:" + startingAddress + ",quantity:" + quantity + ",integerArray:" + Arrays.toString(integerArray));
		return new ReadInputRegistersResponse(array);
	}

	/**
	 * 读保持寄存器（测试过了）
	 * @param unitIdentifier 就是 slaveId，从站地址
	 * @param request
	 * @return
	 */
	@Override
	public ReadHoldingRegistersResponse readHoldingRegisters(short unitIdentifier, ReadHoldingRegistersRequest request) {
		int[] registers = new int[request.getQuantityOfInputRegisters()];
		short slaveId = unitIdentifier;//从站编号
		short functionCode = request.getFunctionCode();//功能码
		int startingAddress = request.getStartingAddress();//起始地址，寄存器读取开始地址
		int address = request.getAddress();//起始地址
		int quantity = request.getQuantityOfInputRegisters();//批量连续读取数量
		int value = request.getValue();////读取的寄存器数量，连续读取数量
		Integer[] integerArray = DataMap.getBatchValue(slaveId,functionCode,startingAddress,quantity);
		int[] array = Arrays.stream(integerArray).mapToInt(Integer::intValue).toArray();
		logger.debug("readHoldingRegisters,unitIdentifier:" + unitIdentifier + ",functionCode:" + functionCode + ",startingAddress:" + startingAddress + ",quantity:" + quantity + ",integerArray:" + Arrays.toString(integerArray));
		return new ReadHoldingRegistersResponse(array);
	}

	@Override
	public WriteSingleCoilResponse writeSingleCoil(short unitIdentifier, WriteSingleCoilRequest request) {
		ChannelSender channelSender = ModbusConsoleApp.setup.getChannelSender(unitIdentifier);
		if(channelSender != null && channelSender.getChannel() != null){
			try {
				boolean state = false;
				if(request.getValue() == 0){
					state = false;
				}else{
					state = true;
				}
				logger.debug("writeSingleCoil,unitIdentifier:" + unitIdentifier + ",OutputAddress:" + request.getOutputAddress() + ",state:" + state);
				return channelSender.writeSingleCoil(request.getOutputAddress(),state);
			}catch (Exception e){
				logger.error("writeSingleCoil Exception",e);
			}
		}
		return new WriteSingleCoilResponse(request.getOutputAddress(), request.isState());
	}

	@Override
	public WriteSingleRegisterResponse writeSingleRegister(short unitIdentifier, WriteSingleRegisterRequest request) {
		ChannelSender channelSender = ModbusConsoleApp.setup.getChannelSender(unitIdentifier);
		if(channelSender != null && channelSender.getChannel() != null){
			try {
				logger.debug("writeSingleRegister,unitIdentifier:" + unitIdentifier + ",RegisterAddress:" + request.getRegisterAddress() + ",RegisterValue:" + request.getRegisterValue());
				return channelSender.writeSingleRegister(request.getRegisterAddress(),request.getRegisterValue());
			}catch (Exception e){
				logger.error("writeSingleRegister Exception",e);
			}
		}
		return new WriteSingleRegisterResponse(request.getRegisterAddress(), request.getRegisterValue());
	}

	@Override
	public WriteMultipleCoilsResponse writeMultipleCoils(short unitIdentifier, WriteMultipleCoilsRequest request) {
		ChannelSender channelSender = ModbusConsoleApp.setup.getChannelSender(unitIdentifier);
		if(channelSender != null && channelSender.getChannel() != null){
			try {
				logger.debug("writeMultipleCoils,unitIdentifier:" + unitIdentifier + ",StartingAddress:" + request.getStartingAddress() + ",QuantityOfOutputs:" + request.getQuantityOfOutputs() + ",OutputsValue:" + request.getOutputsValue().toString());
				return channelSender.writeMultipleCoils(request.getStartingAddress(),request.getQuantityOfOutputs(),request.getOutputsValue());
			}catch (Exception e){
				logger.error("writeMultipleCoils Exception",e);
			}
		}
		return new WriteMultipleCoilsResponse(request.getStartingAddress(), request.getQuantityOfOutputs());
	}

	@Override
	public WriteMultipleRegistersResponse writeMultipleRegisters(short unitIdentifier, WriteMultipleRegistersRequest request) {
		ChannelSender channelSender = ModbusConsoleApp.setup.getChannelSender(unitIdentifier);
		if(channelSender != null && channelSender.getChannel() != null){
			try {
				logger.debug("writeMultipleRegisters,unitIdentifier:" + unitIdentifier + ",StartingAddress:" + request.getStartingAddress() + ",QuantityOfRegisters:" + request.getQuantityOfRegisters() + ",Registers:" + Arrays.toString(request.getRegisters()));
//				int startingAddress = request.getStartingAddress();
//				int quantity = request.getQuantityOfRegisters();
//				int[] registers = request.getRegisters();
//				for(int i=0;i<quantity;i++){
//					int value = registers[i];
					//channelSender.writeSingleRegister(startingAddress + i,value);
//				}
				return channelSender.writeMultipleRegisters(request.getStartingAddress(),request.getQuantityOfRegisters(),request.getRegisters());//
			}catch (Exception e){
				logger.error("writeMultipleRegisters Exception",e);
			}
		}
		return new WriteMultipleRegistersResponse(request.getStartingAddress(), request.getQuantityOfRegisters());
	}
}
